#include <stdio.h>
#include <err.h>
#include <errno.h>
#include <sysexits.h>
#include <sys/select.h>
#include <string.h>
#include <unistd.h>

#include "serial.h"
#include "hexdump.h"
#include "sniff232.h"

int
prepare_sniffer_mode(config_t *cfg)
{
	printf("preparing sniffer\n");
    if ( (cfg->P_arg == NULL) || (cfg->p_arg == NULL) ||
         (cfg->port1_spd == 0)
       )
    {
        errx(EX_USAGE, "Insufficient arguments, try running with -h");
    }
    
    cfg->fd1 = open_line(cfg->P_arg, cfg->port1_spd);
    if (cfg->fd1 == -1)
        errx(EX_OSERR, "Problem opening %s: %s", cfg->P_arg, strerror(errno));
    
		
    cfg->fd2 = open_line(cfg->p_arg, cfg->port1_spd);
    if (cfg->fd2 == -1)
    {
        close(cfg->fd1);
        errx(EX_OSERR, "Problem opening %s: %s", cfg->p_arg, strerror(errno));
    }
	
	cfg->dump_stream = stdout;
	if (cfg->dump_filename)
	{
		cfg->dump_stream = fopen(cfg->dump_filename, "w");
		if (!cfg->dump_stream)
			errx(EX_OSERR, "fopen: %s", strerror(errno));
	}

    printf("%s ready to run (%s at %d bps, %s at %d bps)\n",
        cfg->progname, cfg->N_arg, cfg->port1_spd, cfg->n_arg, cfg->port2_spd);
	
	return 0;
}

void
run_sniffer(config_t *cfg)
{
    fd_set readset;
    char buf[BUFSZ];
    int rd, err, maxfd;
	struct hexdump_state_t *state;
	struct timeval tv;
	
	int port1_needflush = 1, port2_needflush = 1;
	
	printf("running sniffer\n");
	
	tv.tv_sec = 0;
	tv.tv_usec = 100000;
    
    maxfd = MAX(cfg->fd1, cfg->fd2) + 1;

	state = hexdump_init(HDSTEP, cfg->dump_stream);

	FD_ZERO(&readset);	
	while(!ctrlc)
	{
		FD_SET(cfg->fd1, &readset);
		FD_SET(cfg->fd2, &readset);
		
		err = select(maxfd, &readset, NULL, NULL, &tv);
		if ( err < 0 )
		{
			if ( errno == EINTR )
			    continue;
			    
			cleanup(cfg);
			errx(EX_OSERR, "select: %s", strerror(errno));
		}
		
		if ( err == 0 )
		{
			hexdump_flush(state);
		}
		
		/**** BAD CODE BEGIN ****/
		
		if (FD_ISSET(cfg->fd1, &readset))
		{
			FD_CLR(cfg->fd1, &readset);
            rd = xfer(cfg->fd1, cfg->fd2, buf, BUFSZ);
            if (err < 0)
            {
                cleanup(cfg);
                errx(EX_OSERR, "xfer: %s\n", strerror(errno));
            }
			
			if (cfg->flags & OBUF_ENABLE)
			{
				port2_needflush = 1;
				if (port1_needflush)
				{
					port1_needflush = 0;
					hexdump_flush(state);
					fprintf(cfg->dump_stream, "%s -> %s\n", cfg->N_arg, cfg->n_arg);
				}
				buffered_hexdump(buf, rd, state);
			}
			else
			{
				fprintf(cfg->dump_stream, "%s -> %s\n", cfg->N_arg, cfg->n_arg);
				hexdump(buf, rd, HDSTEP, cfg->dump_stream);
			}
		}
		
		
		if (FD_ISSET(cfg->fd2, &readset))
		{
			FD_CLR(cfg->fd2, &readset);
            rd = xfer(cfg->fd2, cfg->fd1, buf, BUFSZ);
            if (err < 0)
            {
                cleanup(cfg);
                errx(EX_OSERR, "xfer: %s\n", strerror(errno));
            }
			
			if (cfg->flags & OBUF_ENABLE)
			{
				port1_needflush = 1;
				if (port2_needflush)
				{
					port2_needflush = 0;
					hexdump_flush(state);
					fprintf(cfg->dump_stream, "%s -> %s\n", cfg->n_arg, cfg->N_arg);
				}
				buffered_hexdump(buf, rd, state);
			}
			else
			{
				fprintf(cfg->dump_stream, "%s -> %s\n", cfg->n_arg, cfg->N_arg);
				hexdump(buf, rd, HDSTEP, cfg->dump_stream);
			}
		}
		
		/**** BAD CODE END ****/
	}
	
	hexdump_free(state);
}

